#ifndef DATABASE_LINKER_H
#define DATABASE_LINKER_H

#include "../Malloc.hpp"

namespace DBServer
{
namespace Database
{

template<typename T>
class ListNode {
public:
    T           data; 
    ListNode    *next;
    ListNode    *prev;      
};

template<typename T>
class ListIter {
public:
    ListNode<T> *node;
    
    bool operator++() {
        if (node->next == nullptr) 
            return false;
        else 
            node = node->next;
        return true;
    }

    bool operator--() {
        if (node->prev == nullptr)
            return false;
        else 
            node = node->prev;
        return true;
    }

    bool operator==(ListIter<T> iter) { return (node->data == iter.node->data); }
    bool operator!=(ListIter<T> iter) { return (node->data != iter.node->data); }
};

template<typename T>
class Linker {
public:
    Linker();
    ~Linker();

    int size();                     // get the size of the linker
    ListNode<T>& get_head();        // get the head of the linker
    ListNode<T>& get_tail();        // get the head of the linker
    ListIter<T>* end();             // the tail of the linker
    void push_front(const T&);       
    void push_back(const T&);
    ListIter<T>* get_iterator();
    void iter_insert(ListIter<T>*, const T&);   // insert front iter->node
    ListIter<T>* find(const T&);
    ListIter<T>* get(int);
    void rotale(ListIter<T>*);      // pop and push front
    void erase(const T&);
    void erase(ListIter<T>*);

    Linker(const Linker&) = delete;
    const Linker& operator=(const Linker&) = delete;
    Linker(const Linker&&) = delete;
    const Linker&& operator=(const Linker&&) = delete;
    
private:
    ListNode<T>* create_node(const T&);
    void removed(ListIter<T>*);

private:
    ListNode<T>         *head;
    ListNode<T>         *tail;
    ListIter<T>         *_end;
    int                 len;
};

template<typename T>
ListNode<T>* Linker<T>::create_node(const T& t) {
    ListNode<T> *node = New<ListNode<T>>();
    node->data = t;
    node->next = nullptr;
    node->prev = nullptr;
    return node;
}

template<typename T>
void Linker<T>::removed(ListIter<T> *iter)
{
    int counter = 0;
    ListIter<T> *_iter = get_iterator();
    while (counter < len && (*iter) != (*_iter)) 
    {
        ++counter;
        ++(*_iter);
    }
    if (counter == len) return;
    if (iter->node->prev)   // head
        iter->node->prev->next = iter->node->next;
    else
        head = iter->node->next;
    if (iter->node->next)
        iter->node->next->prev = iter->node->prev;
    else
        tail = iter->node->prev;
    Delete(_iter);
}

template<typename T>
Linker<T>::Linker() 
    : len(0)
{
    head = nullptr;
    tail = nullptr;
    _end = New<ListIter<T>>();
    _end->node = nullptr; 
}

template<typename T>
Linker<T>::~Linker() {
    Delete(_end);
    ListNode<T> *tmp = head;
    while (head != nullptr) {
        head = head->next;
        Delete(tmp);
    }
}

template<typename T>
int Linker<T>::size() { return len; }

template<typename T>
ListNode<T>& Linker<T>::get_head() { return *head; }

template<typename T>
ListNode<T>& Linker<T>::get_tail() { return *tail; }

template<typename T>
ListIter<T>* Linker<T>::end() { return _end; }

template<typename T>
void Linker<T>::push_front(const T& t) {
    ListNode<T> *node = create_node(t);
    if (head) {
        head->prev = node;
        node->next = head;
    }
    if (!tail) tail = node;
    head = node;
    ++len;
}

template<typename T>
void Linker<T>::push_back(const T& t) {
    ListNode<T> *node = create_node(t);
    if (tail) {
        tail->next = node;
        node->prev = tail;
    }
    if (!head) head = node;
    tail = node;
    ++len;
}

template<typename T>
ListIter<T>* Linker<T>::get_iterator() {
    ListIter<T> *iter = New<ListIter<T>>();
    iter->node = head;
    return iter;
}

template<typename T>
void Linker<T>::iter_insert(ListIter<T> *iter, const T& t) {
    ListNode<T>* node = create_node(t);
    if (iter->node->prev == nullptr) // head 
    {
        iter->node->prev = node;
        node->next = iter->node;
        head = node;
    }
    else if (iter->node->next == nullptr)   // tail
    {
        iter->node->next = node;
        node->prev = iter->node;
        tail = node;
    }
    else 
    {
        iter->node->prev->next = node;
        node->next = iter->node;
        node->prev = iter->node->prev;
        iter->node->prev = node;
    }
    ++len;
}

template<typename T>
ListIter<T>* Linker<T>::find(const T& t) {
    ListIter<T> *iter = get_iterator();
    if (iter->node->data == t) return iter;
    while (++(*iter) && iter->node->data != t);
    if (iter->node->data == t) return iter;
    Delete(iter);
    return this->end();
}

template<typename T>
ListIter<T>* Linker<T>::get(int index) {
    if (index > len) return this->end();
    int counter = index;
    ListIter<T> *iter = get_iterator();
    while (--index) ++(*iter);
    return iter;
}

template<typename T>
void Linker<T>::erase(const T& t) {
    ListIter<T> *iter = get_iterator();
    while (iter->node->data != t) 
        if (++(*iter)) break;
    
    if (iter == nullptr) return;
    // erase 
    iter->node->next->prev = iter->node->prev;
    iter->node->prev->next = iter->node->next;
    Delete(iter->node);
    Delete(iter);
    --len;
}

template<typename T>
void Linker<T>::erase(ListIter<T>* iter) {
    removed(iter);
    Delete(iter->node);
    Delete(iter);
    --len;
}

template<typename T>
void Linker<T>::rotale(ListIter<T> *iter) {
    removed(iter);
    head->prev = iter->node;
    iter->node->prev = nullptr;
    iter->node->next = head;
    head = iter->node;
}


} // namespace Database    
} // namespace DBServer



#endif